

#include "EventSystem.h"

//	Register Client.
void CEventSystem::RegisterClient(EVENTID eventID, IListener* pClient)
{
	//	Error check to make sure the client exists and hasn't been registered for this event already.
	if (!pClient || AlreadyRegistered(eventID, pClient))	return;

	//	Register (Build) the database of clients.
	m_ClientDatabase.insert( make_pair(eventID, pClient) );
}

//	Unregister Client
void CEventSystem::UnregisterClient(EVENTID eventID, IListener *pClient)
{
	//	Make an iterator that will iterate all of our clients that
	//	should be receiveing this event
	pair<multimap<EVENTID, IListener*>::iterator,
		 multimap<EVENTID, IListener*>::iterator> range;

	//	Find all of the clients that are able to receive this event.
	range = m_ClientDatabase.equal_range(eventID);

	//	Go through the list of clients that are able to receive this event.
	for(multimap<EVENTID, IListener*>::iterator mmIter = range.first;
					mmIter != range.second; mmIter++)
	{
		//	check if the pointer is equal to the client
		if((*mmIter).second == pClient)
		{
			//	remove the client from the list
			mmIter = m_ClientDatabase.erase(mmIter);
			break;
		}
	}
}

//	Unregister Client All
void CEventSystem::UnregisterClientAll(IListener *pClient)
{
	multimap<string, IListener*>::iterator mmIter = m_ClientDatabase.begin();

	while(mmIter !=m_ClientDatabase.end())
	{
		if((*mmIter).second == pClient)
		{
			mmIter = m_ClientDatabase.erase(mmIter);
		}
		else
			mmIter++;
	}
}

//	Dispatch Event.
bool CEventSystem::DispatchEvent(CEvent *pEvent)
{
	//	Make an iterator that will iterate all of our clients that
	//	should be receiveing this event
	pair<multimap<EVENTID, IListener*>::iterator,
		 multimap<EVENTID, IListener*>::iterator> range;

	//	Find all of the clients that are able to receive this event.
	
	range = m_ClientDatabase.equal_range(pEvent->GetEventID());

	
	//	Go through the linked list of clients that are able to receive this event.
	for(multimap<EVENTID, IListener*>::iterator mmIter = range.first; mmIter != range.second; mmIter++)
	{
		//	Pass this event to the client
		if((*mmIter).second->HandleEvent(pEvent) == false)
		{
			return false;
			break;
		}
	}

	return true;
}

bool CEventSystem::AlreadyRegistered(EVENTID eventID, IListener* pClient)
{
	bool bIsAlreadyRegistered = false;

	//	Make an iterator that will iterate all of our clients that
	//	should be receiveing this event
	pair<multimap<EVENTID, IListener*>::iterator,
		 multimap<EVENTID, IListener*>::iterator> range;

	//	Find all of the clients that are able to receive this event.
	range = m_ClientDatabase.equal_range(eventID);

	//	Go through the list of clients that are able to receive this event.
	for(multimap<EVENTID, IListener*>::iterator mmIter = range.first;
					mmIter != range.second; mmIter++)
	{
		//	check if the pointer is equal to the client
		if((*mmIter).second == pClient)
		{
			bIsAlreadyRegistered = true;
			break;
		}
	}

	return bIsAlreadyRegistered;
}


void CEventSystem::SendEvent(EVENTID eventID, float time, void* pData, unsigned int eventActor, unsigned int eventTarget)
{
	//	Push my event into the list.
	CEvent newEvent(eventID, time, pData, eventActor, eventTarget);

	if(processing)
		m_ToProcess.push_back(newEvent);
	else
		m_CurrentEvents.push_back(newEvent);
}

void CEventSystem::ProcessEvents(float dt)
{
	//	Go through my list of events that are waiting to be processed.
	list<CEvent>::iterator itt;

	while(m_ToProcess.empty() == false)
	{
		m_CurrentEvents.push_back(m_ToProcess.front());
		m_ToProcess.pop_front();
	}

	processing = true;
	itt = m_CurrentEvents.begin();
	while(itt != m_CurrentEvents.end())
	{
		bool cont = true;
		switch((*itt).GetEventType())
		{
		case event_normal:
			{
				cont = DispatchEvent(&(*itt));
				
				if(m_CurrentEvents.empty() == false)
					itt = m_CurrentEvents.erase(itt);
				
				break;
			}
		case event_timed:
			{
				float time = (*itt).GetThreshold();
				time -= dt;
				(*itt).SetThreshold(time);

				if(time <= 0.0f)
				{
					DispatchEvent(&(*itt));
					itt = m_CurrentEvents.erase(itt);
				}
				else
				{
					itt++;
				}	
			}
			break;
		case event_crossed:
			{
				CBase * actor = CObjectManager::GetInstance()->GetObjectById((*itt).GetActor());
				CBase * target = CObjectManager::GetInstance()->GetObjectById((*itt).GetTarget());

				if(actor != NULL && actor->GetPosX() >= (*itt).GetThreshold())
				{
					if(target == NULL)
					{
						target = NULL;
					}
					else
					{
						(*itt).SetParam(target);
					}
					DispatchEvent(&(*itt));
					itt = m_CurrentEvents.erase(itt);
				}
				else
				{
					itt++;
				}
			}
			break;
		}

		if(cont == false)
			break;
	}

	processing = false;
}

void CEventSystem::ClearEvents(void)
{
	m_CurrentEvents.clear();
}

void CEventSystem::ShutdownEventSystem(void)
{
	m_ClientDatabase.clear();
}
